#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "global.h"
#include "parse.h"

//----------------------------------------------------------
CO_NAME *CO_HEAD = NULL,*CO_TAIL = NULL;
H_NAME *H_HEAD = NULL,*H_TAIL = NULL;

char *ENAME = NULL;//最后生成的可执行文件
char *FLAGS = NULL;//保存gcc的编译选项
char *LIBS = NULL;//gcc链接使用的库或者其他目标文件

//----------------------------------------------------------
//把c文件名加入链表
static void co_add(char cname[]);
//把h文件名加入链表
static void h_add(char hname[]);

//----------------------------------------------------------

/*
 * 把解析出来的c文件名存放如链表中,以便之后进行
 * 时间的判断及获得相应的obj文件
 */
static void co_add(char cname[]){
    CO_NAME *temp = (CO_NAME*)malloc(sizeof(CO_NAME)); 
    if(!CO_HEAD){
        CO_HEAD = CO_TAIL = temp;
        CO_TAIL->next = NULL;
    }else{
        CO_TAIL->next = temp;
        CO_TAIL = temp;
        CO_TAIL->next = NULL;
    }
    strcpy(temp->cname,cname);
    strcpy(temp->oname,cname);//相应的obj文件名
    temp->oname[strlen(cname) - 1] = 'o';
    if(access(temp->oname,F_OK) < 0) //测试文件是否存在
        temp->oname[0] = '\0';
    return;
}

/*
 * 把解析出来的h文件名存放如链表中,以便之后进行
 * 时间的判断
 */
static void h_add(char hname[]){
    H_NAME *temp = (H_NAME*)malloc(sizeof(H_NAME)); 
    if(!H_HEAD){
        H_HEAD = H_TAIL = temp;
        H_TAIL->next = NULL;
    }else{
        H_TAIL->next = temp;
        H_TAIL = temp;
        H_TAIL->next = NULL;
    }
    strcpy(temp->hname,hname);
    return;
}

/*
 * 分析每行读取到的文件,并分别存储到指定的全局变量结构中
 */
void split_store(char *line,char start) {
    if(start == 'E'){       //处理生成最终可执行程序的行
        if(!ENAME){
            int step = 1;
            while(isspace(line[++step]));//跳过所有空白
            ENAME = (char *)malloc(strlen(line));
            strcpy(ENAME,line + step * sizeof(char));
            return;
        }else //出现重复的E开头的行
            err_quit(MORE_ELINE);
    }else if(start == 'F'){ //处理编译选项
        int len = (FLAGS? strlen(FLAGS):0);
        FLAGS = (char *)realloc(FLAGS,len + strlen(line)); //扩展存储空间
        strcat(FLAGS,line + sizeof(char));  //把所有编译选项或链接的库等保存成一个字符串
        return;
    }else if(start == 'L'){ //处理链接的额外库等
        int len = (LIBS? strlen(LIBS):0);
        LIBS = (char *)realloc(LIBS,len + strlen(line)); //扩展存储空间
        strcat(LIBS,line + sizeof(char));  //把所有编译选项或链接的库等保存成一个字符串
        return;
    }

    char temp[NAME_MAX];//临时存储文件名
    int start_pos = 1;  
    while(isspace(line[++start_pos]));//非空白开始的位置,以防有多个空白
    for(int i = start_pos,j = 0;line[i] != '\0';){
        temp[j++] = line[i++];
        if(isspace(line[i]) || line[i] == '\0'){  
            temp[j] = '\0';          //添加结束符
            if(start == 'C')
                co_add(temp);
            else if(start == 'H')
                h_add(temp);
            j = 0;
            while(isspace(line[++i])); //跳过所有空白
        }
    }
    return;
}

/*
 *测试函数,显示解析过程的一些信息以便察看
 */
void parse_info(void){
    printf("=====================================================================\n");
    printf("                            读取文件并解析                           \n");
    printf("=====================================================================\n");
    printf("可执行文件名  ->   %s\n",ENAME);
    printf("编译选项      ->   %s\n",FLAGS);
    printf("链接的额外库  ->   %s\n",LIBS);
    printf("所有C文件     ->   ");
    CO_NAME *cnode = CO_HEAD;
    while(cnode){
        printf("%s   ",cnode->cname);
        cnode = cnode->next;
    }
    printf("\n所有H文件     ->   ");
    H_NAME *hnode = H_HEAD;
    while(hnode){
        printf("%s   ",hnode->hname);
        hnode = hnode->next;
    }
    printf("\n=====================================================================\n\n");
}
